/*******************************************************************************
 * Copyright 2011 Mauro Luigi Drago (drago.luigi@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.bytenose.extrautils.collect;

import java.util.Iterator;
import java.util.NoSuchElementException;

import com.bytenose.extrautils.annotations.NonNullable;
import com.bytenose.extrautils.annotations.UtilityClass;
import com.bytenose.extrautils.functional.ITuple2;
import com.bytenose.extrautils.functional.ITuple3;
import com.bytenose.extrautils.functional.ITuple4;

import com.google.common.collect.UnmodifiableIterator;

/**
 * Defines methods to materialize non-materialized iterators.
 * @author Mauro Luigi Drago
 *
 */
@UtilityClass
final class Materialization {
	
	/**
	 * Private constructor to avoid instantiation.
	 */
	private Materialization() {
	}
	
	/**
	 * Materializes a non-materialized tuples iterator.
	 * The returned iterator is a non-materialized iterator yielding mutable tuples.
	 * @param <T1> the type of the first argument.
	 * @param <T2> the type of the second argument.
	 * @param tuplesIterator the tuples iterator, cannot be null.
	 * 
	 * @throws NoSuchElementException 
	 * 		if iterators do not yield the same number of elements.
	 * @throws IllegalArgumentException 
	 * 		if some of the {@link NonNullable} arguments are null.
	 */
	@NonNullable
	static <T1,T2> UnmodifiableIterator<ITuple2<T1,T2>> materialize2(
			@NonNullable final Iterator<? extends ITuple2<T1,T2>> tuplesIterator) 
			throws IllegalArgumentException, NoSuchElementException {
		if (tuplesIterator == null) throw new IllegalArgumentException("tuplesIterator");
		
		return new UnmodifiableIterator<ITuple2<T1,T2>>() {
			@Override
			public boolean hasNext() {
				return tuplesIterator.hasNext();
			}
			
			@Override
			public ITuple2<T1,T2> next() throws NoSuchElementException {
				ITuple2<T1,T2> nonMat = tuplesIterator.next();
				return nonMat.materialize();
			}
		};
	}
	
	/**
	 * Materializes a non-materialized tuples iterator.
	 * The returned iterator is a non-materialized iterator yielding mutable tuples.
	 * @param <T1> the type of the first argument.
	 * @param <T2> the type of the second argument.
	 * @param <T3> the type of the third argument.
	 * @param tuplesIterator the tuples iterator, cannot be null.
	 * 
	 * @throws NoSuchElementException 
	 * 		if iterators do not yield the same number of elements.
	 * @throws IllegalArgumentException 
	 * 		if some of the {@link NonNullable} arguments are null.
	 */
	@NonNullable
	static <T1, T2, T3> UnmodifiableIterator<ITuple3<T1,T2,T3>> materialize3(
			@NonNullable final Iterator<? extends ITuple3<T1,T2,T3>> tuplesIterator) 
			throws IllegalArgumentException, NoSuchElementException {
		if (tuplesIterator == null) throw new IllegalArgumentException("tuplesIterator");
		
		return new UnmodifiableIterator<ITuple3<T1,T2,T3>>() {
			@Override
			public boolean hasNext() {
				return tuplesIterator.hasNext();
			}
			
			@Override
			public ITuple3<T1,T2,T3> next() throws NoSuchElementException {
				ITuple3<T1,T2,T3> nonMat = tuplesIterator.next();
				return nonMat.materialize();
			}
		};
	}
	
	/**
	 * Materializes a non-materialized tuples iterator.
	 * The returned iterator is a non-materialized iterator yielding mutable tuples.
	 * @param <T1> the type of the first argument.
	 * @param <T2> the type of the second argument.
	 * @param <T3> the type of the third argument.
	 * @param <T4> the type of the fourth argument.
	 * @param tuplesIterator the tuples iterator, cannot be null.
	 * 
	 * @throws NoSuchElementException 
	 * 		if iterators do not yield the same number of elements.
	 * @throws IllegalArgumentException 
	 * 		if some of the {@link NonNullable} arguments are null.
	 */
	@NonNullable
	static <T1,T2,T3,T4> UnmodifiableIterator<ITuple4<T1,T2,T3,T4>> materialize4(
			@NonNullable final Iterator<? extends ITuple4<T1,T2,T3,T4>> tuplesIterator) 
			throws IllegalArgumentException, NoSuchElementException {
		if (tuplesIterator == null) throw new IllegalArgumentException("tuplesIterator");
		
		return new UnmodifiableIterator<ITuple4<T1,T2,T3,T4>>() {
			@Override
			public boolean hasNext() {
				return tuplesIterator.hasNext();
			}
			
			@Override
			public ITuple4<T1,T2,T3,T4> next() throws NoSuchElementException {
				ITuple4<T1,T2,T3,T4> nonMat = tuplesIterator.next();
				return nonMat.materialize();
			}
		};
	}
}
